#pragma once

#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
#include <cassert>

#define MY_STRING_INIT_CAPACITY 4

namespace my
{
    class string
    {
        friend std::ostream& operator<<(std::ostream& cout, const my::string& str1);

        friend std::istream& operator>>(std::istream& cin, my::string& str1);

    public:

        typedef char* iterator;

    public:

        string(const char* str1 = "")
            :_str(nullptr)
            ,_size(0)
            ,_capacity(0)
        {
            size_t len1 = strlen(str1);
            reserve(len1);
            memcpy(_str, str1, sizeof(char) * (len1 + 1));
            _size = len1;
        }

        string(const string& str1)
            :_str(nullptr)
            ,_size(0)
            ,_capacity(0)
        {
            reserve(str1.capacity());
            memcpy(_str, str1._str, sizeof(char) * (str1._size + 1));
            _size = str1._size;
        }

        ~string()
        {
            if (_str != nullptr)
            {
                delete[] _str;
                _str = nullptr;
            }

            _size = _capacity = 0;
        }

        void swap(string& str1)
        {
            std::swap(_str, str1._str);
            std::swap(_size, str1._size);
            std::swap(_capacity, str1._capacity);
        }

        string& operator=(string str1)
        {
            swap(str1);

            return *this;
        }

        //-----------------------------------------------------------

        iterator begin()
        {
            return _str;
        }

        iterator end()
        {
            return _str + _size;
        }

        //-----------------------------------------------------------

        void push_back(char ch)
        {
            insert(_size, ch);
        }

        void pop_back()
        {
            erase(_size - 1, 1);
        }

        string& operator+=(char ch)
        {
            return insert(_size, ch);
        }

        void append(const char* str1)
        {
            insert(_size, str1);
        }

        string& operator+=(const char* str1)
        {
            return insert(_size, str1);
        }

        void clear()
        {
            _str[_size = 0] = 0;
        }

        const char* c_str() const
        {
            return _str;
        }

        //-----------------------------------------------------------

        size_t size() const
        {
            return _size;
        }

        size_t capacity() const
        {
            return _capacity - 1;
        }

        bool empty() const
        {
            return _size == 0;
        }

        void resize(size_t n, char ch = '\0')
        {
            if (n > _size)
            {
                reserve(n);

                for (int i = _size + 1; i < n; ++i)
                {
                    _str[i] = ch;
                }
            }

            _str[_size = n] = '\0';
        }

        void reserve(size_t n);

        //-----------------------------------------------------------

        char& operator[](size_t index)
        {
            return *(_str + index);
        }

        const char& operator[](size_t index) const
        {
            return *(_str + index);
        }

        //-----------------------------------------------------------

        bool operator<(const string& str1)
        {
            return strcmp(c_str(), str1.c_str()) < 0;
        }

        bool operator>(const string& str1)
        {
            return strcmp(c_str(), str1.c_str()) > 0;
        }

        bool operator==(const string& str1)
        {
            return strcmp(c_str(), str1.c_str()) == 0;
        }

        bool operator<=(const string& str1)
        {
            return !(*this > str1);
        }

        bool operator>=(const string& str1)
        {
            return !(*this < str1);
        }

        bool operator!=(const string& str1)
        {
            return !(*this == str1);
        }

        //-----------------------------------------------------------

        size_t find(char ch, size_t pos = 0) const;

        size_t find(const char* str1, size_t pos = 0) const;

        string& insert(size_t pos, char ch);

        string& insert(size_t pos, const char* str);

        string& erase(size_t pos = 0, size_t len = npos);

        static const size_t npos = -1;

    private:

        char* _str;
        size_t _capacity;
        size_t _size;

    };
}
